﻿using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyServer.Common
{
    /// <summary>
    /// 表示数据操作器基类
    /// </summary>
    public abstract class DataOperatorBase
    {

        #region ========私有变量========

        /// <summary>
        /// 线程锁对象
        /// </summary>
        private static object lockobj = new object();

        /// <summary>
        /// 一个标记，用来标记当前是否已收到停止命令
        /// </summary>
        private bool IsStop = false;

        #endregion

        #region========公有委托========

        /// <summary>
        /// 将要操作数据包的事件委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void BeforeOperateEventHandler(object sender, ref DataBeforeOperateEventArgs e);
        /// <summary>
        /// 操作数据包操作完成的事件委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void OperateCompeleteEventHandler(object sender, ref DataAfterOperateEventArgs e);
        /// <summary>
        /// 发生错误时的事件委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void ErrorCatchedEventHandler(object sender, ref ErrorCatchedEventArgs e);

        #endregion

        #region==========事件==========

        /// <summary>
        /// 数据操作之前
        /// </summary>
        public event BeforeOperateEventHandler BeforeOperateData;

        /// <summary>
        /// 数据操作之后
        /// </summary>
        public event OperateCompeleteEventHandler AfterOperateData;

        /// <summary>
        /// 发生错误时
        /// </summary>
        public event ErrorCatchedEventHandler ErrorCatched;

        #endregion

        #region ==========属性==========

        /// <summary>
        /// 表示数据操作器监听工具的监听工作实例
        /// </summary>
        public Task ListenMainTask { get; private set; }

        /// <summary>
        /// 表示数据操作器的读取工作实例
        /// </summary>
        public Task OperateMainTask { get; private set; }

        /// <summary>
        /// 获取数据操作器的操作队列
        /// </summary>
        public Queue OperateQueue { get; private set; }

        /// <summary>
        /// 获取或设置操作器等待队列的速率
        /// </summary>
        public int ListenRate { get; set; }

        /// <summary>
        /// 表示与处理器关联的数据中心
        /// </summary>
        public DataCenterBase DataCenter { get; private set; }

        #endregion

        #region ========私有函数========

        /// <summary>
        /// 私有侦听函数
        /// </summary>
        protected virtual void DoListen()
        {
            lock (lockobj)
            {
                while (OperateQueue.Count == 0 && IsStop == false)
                {
                    System.Threading.Thread.Sleep(ListenRate);
                }
                if (IsStop)
                {
                    return;
                }
                if (OperateMainTask.Status != TaskStatus.Running)
                {
                    OperateMainTask.Start();
                }
                this.ListenMainTask = new Task(DoListen);
            }
        }

        /// <summary>
        /// 私有操作函数
        /// </summary>
        protected virtual void DoOperate()
        {
            lock (lockobj)
            {
                while (OperateQueue.Count > 0 && IsStop == false)
                {
                    DataPackageCollection pkg = (DataPackageCollection)OperateQueue.Dequeue();
                    DataBeforeOperateEventArgs e = new DataBeforeOperateEventArgs(pkg);
                    DataAfterOperateEventArgs e1;
                    pkg.IsRecive = true;
                    if (pkg.PrecedenceLeft - 1 <= 0 || pkg.PrecedenceLeft > pkg.Precedence)//判定优先级
                    {
                        if (BeforeOperateData != null)
                            BeforeOperateData(this, ref e);
                        if (!e.Canceled)
                        {
                            DataPackageCollection repkg = null;
                            pkg.State = PackageCollectionState.ReadyForOperate;
                            bool IsSucceed=false;
                            try
                            {
                                IsSucceed = Operate(ref pkg, out repkg);
                            }
                            catch (Exception ex)
                            {
                                ErrorCatchedEventArgs e2 = new ErrorCatchedEventArgs(ex, pkg);
                                e2.Operate = ErrorOperate.RemoveCol;
                                if(ErrorCatched!=null)
                                {
                                    ErrorCatched(this,ref e2);
                                }
                                switch(e2.Operate)
                                {
                                    case ErrorOperate.RemoveCol:
                                        continue;
                                    case ErrorOperate.StopSend:
                                        return;
                                    case ErrorOperate.Pass:
                                        break;
                                    case ErrorOperate.ClearQueue:
                                        OperateQueue.Clear();
                                        break;
                                }
                                IsSucceed = false;
                            }
                            e1 = new DataAfterOperateEventArgs(pkg, repkg);
                            e1.IsSucceed = IsSucceed;
                        }
                        else
                        {
                            e1 = new DataAfterOperateEventArgs(pkg, null);
                            e1.IsSucceed = false;
                        }
                        e1.Canceled = e.Canceled;
                        pkg.PrecedenceLeft = pkg.Precedence;
                        if (AfterOperateData != null)
                            AfterOperateData(this, ref e1);
                    }
                    else
                    {
                        pkg.PrecedenceLeft--;
                    }

                    if (!e.Canceled)
                    {
                        if (pkg.State == PackageCollectionState.Operating)
                        {
                            OperateQueue.Enqueue(pkg);
                        }
                    }
                }
                this.OperateMainTask = new Task(DoOperate);
                if (ListenMainTask.Status != TaskStatus.Running)
                    ListenMainTask.Start();

            }
        }

        #endregion

        #region========公用方法========

        /// <summary>
        /// 开始监听处理队列
        /// </summary>
        public virtual void StartListen()
        {
            this.IsStop = false;
            if (ListenMainTask.Status != TaskStatus.Running)
            {
                ListenMainTask = new Task(DoListen);
                ListenMainTask.Start();
            }
        }

        /// <summary>
        /// 停止数据处理器
        /// </summary>
        public virtual void Stop()
        {
            this.IsStop = true;
            while (OperateMainTask.Status == TaskStatus.Running || ListenMainTask.Status == TaskStatus.Running)
            {
                System.Threading.Thread.Sleep(10);
            }
        }

        #endregion

        #region========抽象函数========

        /// <summary>
        /// 开始尝试处理指定包中的数据
        /// </summary>
        /// <param name="pkg">要处理的数据包列表</param>
        /// <param name="RePkg">表示处理完毕要发送的数据包</param>
        /// <returns>是否成功完成一次操作</returns>
        protected abstract bool Operate(ref DataPackageCollection pkg, out DataPackageCollection RePkg);

        #endregion

        #region========构造函数========

        public DataOperatorBase(DataCenterBase Center)
        {
            //初始化工作流
            this.OperateMainTask = new Task(DoOperate);
            this.ListenMainTask = new Task(DoListen);
            //初始化列表
            this.OperateQueue = Queue.Synchronized(new Queue());
            //初始化设定
            this.ListenRate = 10;
            this.DataCenter = Center;
        }

        #endregion


    }

}
